package pl.edu.mimuw.irs.core.model.design.net;

import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import pl.edu.mimuw.irs.core.global.IDManager;
import pl.edu.mimuw.irs.core.model.design.atomic.AtomicSubnet;
import pl.edu.mimuw.irs.core.model.design.exception.InternalDesignException;
import pl.edu.mimuw.irs.core.model.design.exception.InternalDesignException.DesignCause;
import pl.edu.mimuw.irs.core.model.design.resource.Requirement;
import pl.edu.mimuw.irs.core.model.design.resource.Requirements;
import pl.edu.mimuw.irs.core.model.petrinet.Place;
import pl.edu.mimuw.irs.core.model.petrinet.Transition;
import pl.edu.mimuw.irs.core.util.Converter;
import pl.edu.mimuw.irs.core.util.Position;

/**
 * @author Jakub Rauch
 * Created on: 2009-05-07
 */
public class IRSRequirement extends IRSPlace {
	
	private static final long serialVersionUID = 3997013035980030550L;
	
	// *** Attributes
	private Requirements requirements;
	private Map<Requirement, Integer> requirementsMap;
	private int timeUnits;
	private double deviation;
	// Node supports
	private final static Set<Fragmentation> supportedFragmentations;
	static {
		supportedFragmentations = new LinkedHashSet<Fragmentation>();
		supportedFragmentations.add(Fragmentation.NONE);
	}
	public Requirements getRequirements() {
		if (requirements == null) requirements = new Requirements();
		return requirements;
	}
	public Map<Requirement, Integer> getRequirementsMap() {
		requirementsMap = new LinkedHashMap<Requirement, Integer>();
		for (Requirement requirement : getRequirements()) {
			Integer value = requirementsMap.get(requirement);
			if (value == null) {
				requirementsMap.put(requirement, new Integer(1));
			} else {
				requirementsMap.put(requirement, value + 1);
			}
		}
		return requirementsMap;
	}
	public void setRequirements(Requirements requirements) {
		this.requirements = requirements;
	}
	public IRSActivity getActivity() {
		try {
			return Converter.asIRSActivity(getParent().getChildren().get(0)); // XXX dirty
		} catch (Exception ex) {
			throw new InternalDesignException(DesignCause.CO_ACTIVITY_NOT_FOUND, ex, this);
		}
	}
	@Override
	public Set<Fragmentation> getSupportedFragmentations() {
		return supportedFragmentations;
	}
	public int getTimeUnits() {
		return timeUnits;
	}
	public void setTimeUnits(int timeUnits) {
		this.timeUnits = timeUnits;
	}
	public double getDeviation() {
		return deviation;
	}
	public void setDeviation(double deviation) {
		this.deviation = deviation;
	}
	@Override
	public IRSPlaceCopier getCopier() {
		return new IRSRequirementCopier(this);
	}
	
	// *** Constructors

	public IRSRequirement(IDManager idManager, String id, NodeType nodeType, Position position, int tokens, 
			int timeUnits, Requirements requirements) {
		super(idManager, id, nodeType, position, tokens);
		setTimeUnits(timeUnits);
		setRequirements(requirements);
	}
	
	public IRSRequirement(IDManager idManager, String id, NodeType nodeType, Position position, int tokens, int timeUnits) {
		super(idManager, id, nodeType, position, tokens);
		setTimeUnits(timeUnits);
	}
	
	public IRSRequirement(IDManager idManager, String id, NodeType nodeType, Position position, int tokens) {
		this(idManager, id, nodeType, position, tokens, 10);
	}
	
	public IRSRequirement(IDManager idManager, String id, Position position, int tokens) {
		this(idManager, id, NodeType.RESOURCE, position, tokens);
	}

	public IRSRequirement(IDManager idManager, Position position) {
		this(idManager, idManager.getNewId(), position, 0);
	}

	public IRSRequirement(IDManager idManager) {
		this(idManager, new Position());
	}
	
	// *** Methods
	
	public AtomicSubnet getAtomicWorkflow(AtomicSubnet atomicSubnet) {
		if (Fragmentation.NONE.equals(getFragmentation())) {
			Place place = copy(atomicSubnet);
			atomicSubnet.addPlace(place);
			atomicSubnet.getPlacesMap().put(this, place);
			Map<IRSTransition, Transition> transitionsMap = atomicSubnet.getTransitionsMap();
			for (IRSArc arc : getAtomicIncomingArcs()) {
				Transition transition = transitionsMap.get(Converter.asIRSTransition(arc.getTransition()));
				if (transition != null) {
					atomicSubnet.addArc(transition, place, getRequirements().size());
				}
			}
			for (IRSArc arc : getAtomicOutgoingArcs()) {
				Transition transition = transitionsMap.get(Converter.asIRSTransition(arc.getTransition()));
				if (transition != null) {
					atomicSubnet.addArc(place, transition, getRequirements().size());
				}
			}
		} else {
			for (IRSNode node : getChildren()) {
				atomicSubnet = node.getAtomicWorkflow(atomicSubnet);
			}
		}
		return atomicSubnet;
	}
}
